﻿using System;
using System.Collections.Generic;

namespace Patterns.Composite {

    public class AbstractExample {

        public static void Run() {
            // Create a tree structure
            Composite root = new Composite("root");
            root.Add(new Leaf("Leaf A"));
            root.Add(new Leaf("Leaf B"));

            Composite comp = new Composite("Composite X");
            comp.Add(new Leaf("Leaf XA"));
            comp.Add(new Leaf("Leaf XB"));

            root.Add(comp);
            root.Add(new Leaf("Leaf C"));

            // Add and remove a leaf
            Leaf leaf = new Leaf("Leaf D");
            root.Add(leaf);
            root.Remove(leaf);

            // Recursively display tree
            root.Display(1);
        }
    }

    // "Component"
    abstract class Component {
        protected string name;

        // Constructor
        public Component(string name) {
            this.name = name;
        }

        public abstract void Add(Component c);
        public abstract void Remove(Component c);
        public abstract void Display(int depth);
    }

    // "Composite"
    class Composite : Component {
        private List<Component> children = new List<Component>();

        // Constructor
        public Composite(string name)
            : base(name) {}

        public override void Add(Component component) {
            children.Add(component);
        }

        public override void Remove(Component component) {
            children.Remove(component);
        }

        public override void Display(int depth) {
            Console.WriteLine(new String('-', depth) + name);

            // Recursively display child nodes
            children.ForEach(component =>
                component.Display(depth + 2));
        }
    }

    // "Leaf"
    class Leaf : Component {
        // Constructor
        public Leaf(string name)
            : base(name) { }

        public override void Add(Component c) {
            Console.WriteLine("Cannot add to a leaf");
        }

        public override void Remove(Component c) {
            Console.WriteLine("Cannot remove from a leaf");
        }

        public override void Display(int depth) {
            Console.WriteLine(new String('-', depth) + name);
        }
    }
}
